<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>文件查找</title>
</head>

<body>
<div id="app">
    <el-row :gutter="20">
        <el-col :span="16" :offset="3">
            <el-select
                    style="width: 100%"
                    v-model="filePath"
                    filterable
                    remote
                    :disabled="loading"
                    allow-create
                    default-first-option
                    placeholder="请输入搜索文件路径，建议直接从文档管理中复制以免输入错误路径；"
                    :remote-method="viewPath"
                    :loading="loadingSelect">
                <el-option
                        v-for="item in filePaths"
                        :key="item.filePath"
                        :value="item.filePath">
                </el-option>
            </el-select>
        </el-col>
        <el-col :span="2" style="text-align: right">
            <el-button type="primary" icon="el-icon-search" :loading="loading" plain @click="searchFile">查询</el-button>
        </el-col>
    </el-row>
    <el-row :gutter="20">
        <el-col :span="10" :offset="3">
            <el-select v-model="filterFileTypes" multiple placeholder="过滤文件类型" :disabled ="loading"  @change="changeFilterFileType"
                       style="width: 100%">
                <el-option
                        v-for="item in fileTypes"
                        :key="item.value"
                        :label="item.label"
                        :value="item.value">
                </el-option>
            </el-select>
        </el-col>
        <el-col :span="8">
            <el-select
                    style="width: 100%"
                    v-model="keyWords"
                    multiple
                    filterable
                    allow-create
                   :disabled="loading"
                    default-first-option
                    placeholder="请输入关键字">
            </el-select>
        </el-col>
    </el-row>
    <!--    <el-row>-->
    <!--        <el-col :span="2" :offset="3">-->
    <!--            <el-button @click="showFlag = !showFlag">设置</el-button>-->
    <!--        </el-col>-->
    <!--        <transition name="el-zoom-in-top">-->
    <!--            <el-col :span="16" :offset="0" v-show="showFlag">-->
    <!--                <div class="block">-->
    <!--                    <span class="demonstration">输入间隔（时间越短搜索间隔越短 建议设置500ms）</span>-->
    <!--                    <el-slider v-model="inputTime"-->
    <!--                               :max="2000"-->
    <!--                               :min="100"-->
    <!--                               show-input-->
    <!--                               :debounce="300"-->
    <!--                               :format-tooltip="formatInputTime"></el-slider>-->
    <!--                </div>-->
    <!--                <div class="block">-->
    <!--                    <span class="demonstration">搜索文件上限（建议200）</span>-->
    <!--                    <el-slider v-model="maxFileCount"-->
    <!--                               :max="2000"-->
    <!--                               :min="0"-->
    <!--                               show-input-->
    <!--                               :debounce="300"-->
    <!--                               :format-tooltip="formatMaxFileCount"></el-slider>-->
    <!--                </div>-->
    <!--            </el-col>-->
    <!--        </transition>-->
    <!--    </el-row>-->
    <el-row v-show="showProgress">
        <el-col :span="24">
            <el-progress :percentage="rateOfProgress"></el-progress>
        </el-col>
    </el-row>
    <el-row>
        <el-col :span="24" :offset="0">
            <el-alert
                    :title="fileListMessage"
                    :type="messageType"
                    :closable="false"
                    center>
            </el-alert>
            <el-table
                    v-loading="loading"
                    border
                    element-loading-text="拼命加载中"
                    element-loading-spinner="el-icon-loading"
                    element-loading-background="rgba(0, 0, 0, 0.8)"
                    stripe
                    height="65vh"
                    :data="fileListInfo"
                    style="width: 100%">
                <el-table-column type="expand">
                    <template #default="props">
                        <el-form label-position="left" inline class="demo-table-expand">
                            <el-form-item label="文件名称:">
                                <span v-html="props.row.fileNameHtml"></span>
                            </el-form-item>
                            <el-form-item label="文件路径:">
                                <span>{{ props.row.filePath }}</span>
                            </el-form-item>
                            <template v-for="(item,index) in props.row.contentHtml">
                                <el-form-item :label=`上下文(${index+1}):`>
                                    <span v-html="item"></span>
                                </el-form-item>
                            </template>
                        </el-form>
                    </template>
                </el-table-column>
                <el-table-column
                        type="index"
                        label="序号"
                        header-align="center"
                        width="50">
                </el-table-column>
                <el-table-column
                        sortable
                        prop="fileName"
                        label="文件名称"
                        header-align="center"
                        show-overflow-tooltip
                        width="300">
                </el-table-column>
                <el-table-column
                        sortable
                        prop="fileType"
                        label="文件类型"
                        header-align="center"
                        show-overflow-tooltip
                        width="120">
                </el-table-column>
                <el-table-column
                        sortable
                        prop="filePath"
                        label="文件路径(展开)"
                        width="400"
                        show-overflow-tooltip
                        header-align="center">
                </el-table-column>
                <el-table-column
                        sortable
                        prop="keyWord"
                        header-align="center"
                        show-overflow-tooltip
                        width="100"
                        label="关键字">
                </el-table-column>
                <el-table-column
                        prop="content"
                        header-align="center"
                        show-overflow-tooltip
                        label="上下文">
                </el-table-column>
            </el-table>
        </el-col>
    </el-row>
</div>
</body>
<script>
    const fileTypes = [{
        value: '.doc',
        label: 'word(doc)'
    }, {
        value: '.docx',
        label: 'word(docx)'
    }, {
        value: '.pdf',
        label: 'pdf'
    }, {
        value: '.xls',
        label: 'Excel(xls)',
    }, {
        value: '.xlsx',
        label: 'Excel(xlsx)'
    }]
    const Counter = {
        data() {
            return {
                filePath: "", //文件地址
                filePaths: [],  //文件下拉框选择
                fileListMessage: '.........................', //提示信息
                fileListInfo: [], //文件信息
                loading: false, //加载状态
                loadingSelect: false, //加载状态
                fileTypes, // 可选过滤文件类型
                filterFileTypes: ['.doc', '.docx', '.pdf', '.xls', '.xlsx'],//过滤文件类型
                keyWords: [],//关键字
                messageType: "info", //弹窗提示信息
                inputTime: 300, //输入间隔控制
                showFlag: false,
                maxFileCount: 2000, //搜索文件上线
                mayFindCount: 50,  //可能会搜索的文件数量 用于进度条
                rateOfProgress:1, //控制进度条进度
                showProgress:false //控制进度条展示与否
            }
        },
        mounted() {
            this.debouncedGetAnswer = _.debounce(this.viewFile, this.inputTime)
            this.openMessage()
            //偶尔会在输入路径之后直接进入文件搜索
            this.keyWords = [];
        },
        watch: {
            filePath() {
                this.viewFile()
            },
            rateOfProgress(val){
                val = parseInt(val)
                if(val===100){
                    this.rateOfProgress = 0;
                }
                this.showProgress = val !== 0;
            }
        },
        methods: {
            //文件类型改变触发
            changeFilterFileType() {
                this.fileListMessage = "等待用户输入中.............";
                this.messageType = 'info'
                this.debouncedGetAnswer();
            },
            openMessage() {
                this.$notify({
                    title: '路径',
                    message: '路径建议直接从<i style="color: #ff4eb6">文档管理器中复制</i>，以免输入错误路径',
                    offset: 130,
                    dangerouslyUseHTMLString: true,
                    iconClass: "el-icon-moon-night"
                });
                this.$notify({
                    title: 'Word',
                    message: '搜索word上下文展示关键字所在<i style="color: rgba(191,80,246,0.93)">段落</i>',
                    offset: 230,
                    dangerouslyUseHTMLString: true,
                    iconClass: "el-icon-sunny"
                });
                this.$notify({
                    title: 'Excel',
                    message: '搜索excel上下文展示关键字所在<i style="color: #f34a4a">单元格</i>',
                    offset: 310,
                    dangerouslyUseHTMLString: true,
                    iconClass: "el-icon-sugar"
                });
                this.$notify({
                    title: 'PDF',
                    dangerouslyUseHTMLString: true,
                    message: '搜索pdf上下文展示关键字所在<i style="color: #ff972f">行</i><br/>注意：多关键字搜索pdf文件时速度较慢！',
                    offset: 390,
                    iconClass: "el-icon-ice-drink"
                });
            },
            //搜索
            searchFile() {
                if (this.mayFindCount === 0) {
                    this.$alert('该路径下没有可以搜索的文件！', '警告', {
                        confirmButtonText: '确定',
                        type: "warning"
                    })
                    return;
                }
                if (this.filePath === "" || this.filePath === null) {
                    this.$alert('请输入搜索的文件路径！', '警告', {
                        confirmButtonText: '确定',
                        type: "warning"
                    })
                    return;
                }
                if (this.keyWords.length === 0) {
                    this.$alert('请输入搜索关键字！', '警告', {
                        confirmButtonText: '确定',
                        type: "warning"
                    })
                } else if (this.filterFileTypes.length === 0) {
                    this.$confirm('没有选择文件类型，程序目前只支持word、pdf、Excel的搜索， 是否继续？可能会有未知错误', '提示', {
                        confirmButtonText: '确定',
                        cancelButtonText: '取消',
                        type: 'warning'
                    }).then(() => {
                        this.viewFile(true)
                    }).catch(() => {
                    });
                } else {
                    this.viewFile(true)
                }
            },
            //格式化输入间隔时间显示
            formatInputTime(val) {
                return val + 'ms';
            },
            formatMaxFileCount(val) {
                return val + '个';
            },
            //后台
            viewFile(flag) {
                this.fileListMessage = "搜索中"
                this.loading = true;
                this.fileListInfo = [];
                //参数
                const params = {
                    //文件地址
                    filePath: this.filePath,
                    //文件过滤类型
                    filterFileTypes: this.filterFileTypes,
                    //最大文件上限
                    maxFileCount: this.maxFileCount,
                    //可能会搜索的文件
                    mayFindCount: this.mayFindCount
                }
                //搜索的时候才把关键字传递到后台  同时也是后台判断预展示还是搜索
                let socket;
                let uid = Math.round(Math.random()*1000000);
                if (flag) {
                    params.keyWords = this.keyWords;
                    params.uid = uid;
                    socket =  this.openSocket(socket,uid)
                }
                axios.get("viewFile.do", {
                    params: params
                    , paramsSerializer: params => {
                        //序列化数组
                        return Qs.stringify(params, {indices: false})
                    }
                }).then(data => {
                    const cdata = data.data
                    if(!flag){
                        this.mayFindCount = 0;
                    }
                    if (cdata.fileListInfo.length > 0) {
                        this.fileListInfo = cdata.fileListInfo;
                        if (flag) {
                            this.fileListMessage = `搜索个${cdata.findFileCount}文件，匹配上${cdata.fileCount}个   ｜   搜索耗时：${cdata.runTime}秒`
                        } else {
                            this.fileListMessage = `共${cdata.findFileCount}个文件`
                        }
                        this.mayFindCount = cdata.findFileCount
                        this.messageType = 'success';
                    } else {
                        this.fileListMessage = "未找到指定目录，或没有对应文件类型！"
                        this.messageType = 'warning';
                    }
                }).catch(() => {
                    this.fileListMessage = `该目录下文件数量超过${this.maxFileCount}，或者其他异常！`;
                    this.messageType = 'error';
                }).finally(()=>{
                    if(socket!=null){
                        socket.close()
                    }
                    this.loading = false;
                })
            },
            //获取系统路径
            viewPath(query) {
                if (query !== '') {
                    this.loadingSelect = true;
                    setTimeout(() => {
                        axios.get("viewPath.do", {
                            params: {
                                filePath: query
                            }
                        }).then(data => {
                            this.filePaths = data.data
                            this.loadingSelect = false;
                        }).catch(() => {
                            this.loadingSelect = false;
                        })
                    }, this.inputTime)
                } else {
                    this.filePaths = [];
                }

            },
            openSocket(socket,uid) {
                if (typeof (WebSocket) === undefined) {
                    console.log("您的浏览器不支持WebSocket，将不能展示进度条")
                } else {
                    console.log("您的浏览器支持WebSocket")
                    let socketUrl = "ws://localhost:8888/webSocket/" + uid;
                    console.log(socketUrl);
                    if (socket != null) {
                        socket.close();
                        socket = null;
                    }
                    socket = new WebSocket(socketUrl)
                    socket.onopen = function () {
                        console.log("WebSocket开启")
                    }
                    //接收到消息
                    socket.onmessage = (msg)=>{
                        //console.log(msg.data)
                        let temp =  msg.data
                        let rate = temp.substring(0,temp.indexOf("##@@"));
                        let fileName = temp.substring(temp.indexOf("##@@")+4,temp.indexOf("**&&"));
                        let runTime = temp.substring(temp.indexOf("**&&")+4);
                        this.openHTML(fileName,runTime)
                       this.rateOfProgress = parseInt(rate);
                    }
                    socket.onclose = function () {
                        console.log("WebSocket关闭")
                    }
                    socket.onerror = function () {
                        console.log("WebSocket发生了错误")
                    }
                }
                return socket
            },
            openHTML(fileName,runTime) {
                let rt = parseInt(runTime)+1000;
                this.$message({
                    dangerouslyUseHTMLString:true,
                    message: `${fileName}---耗时:<i style="color: #e600ff">${runTime}ms</i>`,
                    type: 'success',
                    iconClass:'el-icon-star-off',
                    duration:rt
                })
            }
        }
    }
</script>
<!-- 引入样式 -->
<link rel="stylesheet" href="//unpkg.com/element-plus/dist/index.css">
<!-- 引入 Vue -->
<script src="//unpkg.com/vue@next"></script>
<!-- 引入组件库 -->
<script src="//unpkg.com/element-plus"></script>
<!-- 引入axios -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<!-- 延时触发函数 -->
<script src="https://cdn.jsdelivr.net/npm/lodash@4.13.1/lodash.min.js"></script>
<!-- 序列化参数 -->
<script src="https://cdn.bootcss.com/qs/6.5.1/qs.min.js"></script>
<script src="../index.js"></script>
<style>
    .el-input {
        width: 100%;
    }

    .el-row {
        margin-top: 30px;
    }

    .demo-table-expand {
        font-size: 0;
    }

    .demo-table-expand label {
        width: 90px;
        color: #99a9bf;
    }

    .demo-table-expand .el-form-item {
        margin-right: 0;
        margin-bottom: 0;
        width: 100%;
    }

    .el-alert__title {
        font-size: 18px;
        line-height: 40px;
    }

</style>
</html>
